//
//  HomeScene.swift
//  home
//
//  Created by Yun Zeng on 2019/1/28.
//  Copyright © 2019 Yun Zeng. All rights reserved.
//

import Foundation

enum SceneState: String {
    // 空闲状态: 场景操作没有达到状态也没有在执行
    case idle = "idle"
    // 正在执行场景动作
    case executing = "executing"
    // 活跃状态: 场景需要执行的动作都已经达到指定的状态
    case activated = "activated"
}

// 家庭场景
class HomeScene: Codable {
    var id: String
    var name: String
    var icon: String
    var type: String
    var actions: [HomeAction]
    var state: SceneState = .idle
    
    enum SceneType: String {
        case base = "base"
        case custom = "custom"
    }
    
    private enum CodingKeys: String, CodingKey {
        case id
        case name
        case icon
        case type
        case actions
    }
    
    init(id: String, name: String, type: String) {
        self.id = id
        self.name = name
        self.icon = ""
        self.type = type
        self.actions = [HomeAction]()
    }
}

extension HomeScene: CustomStringConvertible {
    var description: String {
        let data = try! JSONEncoder().encode(self)
        return String(data: data, encoding: .utf8)!
    }
}

// 家庭场景管理
class HomeSceneManager: Codable {
    var scenes: [HomeScene]
    var home: Home?
    
    init(scenes: [HomeScene], home: Home? = nil) {
        self.scenes = scenes
        self.home = home
    }
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(self.scenes)
    }
    
    public required convenience init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let scenes = try container.decode([HomeScene].self)
        self.init(scenes: scenes)
    }
}

extension HomeSceneManager {
    struct ExecuteInfo: Codable {
        var type: String
        var scene: String
    }
    
    func getSceneById(id: String) -> HomeScene? {
        for scene in self.scenes {
            if scene.id == id {
                return scene
            }
        }
        return nil
    }
    
    // 执行场景
    func execute(scene: HomeScene) -> Bool {
        let info = ExecuteInfo(type: "execute", scene: scene.id)
        let msg = CloudMessage(path: HomeMessagePath.scene.rawValue, method: .post, object: info)
        msg.home = self.home?.id
        if CloudClient.instance.state != .transfer {
            return false
        }
        scene.state = .executing
        CloudClient.instance.sendMessage(msg: msg)
        return true
    }
    
    func checkSceneIsActived(scene: HomeScene) -> Bool {
        if self.home == nil {
            return false
        }
        return scene.checkActionsExecuted(actions: scene.actions, home: self.home!)
    }
    
    func stateRefresh() {
        for scene in self.scenes {
            if self.checkSceneIsActived(scene: scene) == true {
                scene.state = .activated
            } else {
                if scene.state == .activated {
                    scene.state = .idle
                }
            }
        }
    }
}

// 检查场景是否执行
extension HomeScene {
    func checkActionsExecuted(actions: [HomeAction], home: Home) -> Bool {
        for action in actions {
            guard let characteritisc = home.containerManager.findService(aid: action.aid, sid: action.sid)?.findCharacteristic(id: action.cid) else {
                return false
            }
            if action.isExecuted(characteristic: characteritisc) == false {
                return false
            }
        }
        return true
    }
}


// 动作是否执行
extension HomeAction {
    func isExecuted(characteristic: HMCharacteristic) -> Bool {
        switch characteristic.format {
        case .bool:
            if let current = characteristic.value?.toValueBool(),
                let target = self.value.toValueBool(), current == target {
                return true
            }
            return false
            
        case .uint8, .uint16, .uint32, .int32:
            if let current = characteristic.value?.toValueInt(),
                let target = self.value.toValueInt(), current == target {
                return true
            } else {
                return false
            }
            
        case .float:
            guard let current = characteristic.value?.toValueFloat() else {
                return false
            }
            guard let target = self.value.toValueFloat() else {
                return false
            }
            if let step = characteristic.stepValue?.toValueFloat() {
                if (target > current && target - current < step)
                    || (target < current && current - target < step) {
                    return true
                } else {
                    return false
                }
            } else {
                if current == target {
                    return true
                }
                return false
            }
            
        default:
            return false
        }
    }
}

extension HomeSceneManager: CustomStringConvertible {
    var description: String {
        let data = try! JSONEncoder().encode(self)
        return String(data: data, encoding: .utf8)!
    }
}






